package com.xzy.spring.main;

import com.xzy.spring.business.entity.AuthorEntity;
import com.xzy.spring.business.entity.BaseEntity;
import com.xzy.spring.business.entity.CatEntity;
import com.xzy.spring.business.entity.UserEntity;
import com.xzy.spring.config.BeansConfig;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

/**
 * @author xzy
 * @date 2021-02-08 11:17
 * 说明：
 */
public class BeanRegisterMain {

    public static void main(String[] args) {
        propertiesAssigment();
    }

    /**
     * 单例Bean
     */
    private static void singletonBean() {
        ApplicationContext applicationContext = getAnnotationConfigApplicationContext();
        UserEntity userEntityPrototypeAnn1 = applicationContext.getBean("userEntitySingletonAnn", UserEntity.class);
        UserEntity userEntityPrototypeAnn2 = applicationContext.getBean("userEntitySingletonAnn", UserEntity.class);
        System.out.println(userEntityPrototypeAnn1);
        System.out.println(userEntityPrototypeAnn2);
        System.out.println(userEntityPrototypeAnn1 == userEntityPrototypeAnn2);
    }

    /**
     * 原型Bean
     */
    private static void prototypeBean() {
        ApplicationContext applicationContext = getAnnotationConfigApplicationContext();
        UserEntity userEntityPrototypeAnn1 = applicationContext.getBean("userEntityPrototypeAnn", UserEntity.class);
        UserEntity userEntityPrototypeAnn2 = applicationContext.getBean("userEntityPrototypeAnn", UserEntity.class);
        System.out.println(userEntityPrototypeAnn1);
        System.out.println(userEntityPrototypeAnn2);
        System.out.println(userEntityPrototypeAnn1 == userEntityPrototypeAnn2);
    }

    /**
     * 懒加载单例Bean
     */
    private static void singletonLazyBean() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = getAnnotationConfigApplicationContext();
        printBeans(annotationConfigApplicationContext);
        annotationConfigApplicationContext.getBean("userEntitySingletonLazyAnn", UserEntity.class);
    }

    /**
     * 使用@Import + ImportSelector 注册Bean
     */
    private static void importSelector() {
        // 观察IOC容易中是否已经存在MyImportSelector要求的Bean
        printBeans(getAnnotationConfigApplicationContext());
    }

    /**
     * 使用@Import + ImportBeanDefinitionRegistrar 注册Bean
     */
    private static void importBeanDefinitionRegistrar() {
        // 观察IOC容器中是否已经存在MyImportBeanDefinitionRegistrar要求的Bean
        printBeans(getAnnotationConfigApplicationContext());
    }

    /**
     * 使用FactoryBean注册Bean
     */
    private static void factoryBean() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = getAnnotationConfigApplicationContext();
        printBeans(annotationConfigApplicationContext);

        Object actualBean = annotationConfigApplicationContext.getBean("myFactoryBean");
        System.out.println("实际类型：" + actualBean.getClass());
        System.out.println(actualBean);

        // 获取BeanFactory
        Object factoryBean = annotationConfigApplicationContext.getBean(BeanFactory.FACTORY_BEAN_PREFIX + "myFactoryBean");
        System.out.println(factoryBean.getClass());
        printBeans(annotationConfigApplicationContext);
    }

    /**
     * 单例Bean，指定初始化、销毁方法
     */
    private static void singletonBeanInitAndDestroy() {
        // 创建、初始化：单例&饿汉Bean在IOC容器创建时被创建和初始化
        AnnotationConfigApplicationContext annotationConfigApplicationContext = getAnnotationConfigApplicationContext();

        BaseEntity baseEntitySingleTonAnn = annotationConfigApplicationContext.getBean("baseEntitySingleTonAnn", BaseEntity.class);
        System.out.println(baseEntitySingleTonAnn);

        // 销毁：单例Bean在IOC容器关闭时销毁
        annotationConfigApplicationContext.close();
        System.out.println(baseEntitySingleTonAnn);
    }

    /**
     * 原型Bean，指定初始化、销毁方法
     */
    private static void prototypeBeanInitAndDestroy() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = getAnnotationConfigApplicationContext();

        // 创建、初始化：原型Bean现用现创
        BaseEntity baseEntityPrototypeAnn = annotationConfigApplicationContext.getBean("baseEntityPrototypeAnn", BaseEntity.class);
        System.out.println(baseEntityPrototypeAnn);

        // 销毁：使用者自行负责原型Bean的销毁
        annotationConfigApplicationContext.close();
        System.out.println(baseEntityPrototypeAnn);

        baseEntityPrototypeAnn.destroy();
        System.out.println(baseEntityPrototypeAnn);
    }

    /**
     * 通过实现InitializingBean和DisposableBean接口，自定义Bean的初始化和销毁流程
     */
    private static void initializingAndDisposableBean() {
        // 创建IOC容器
        AnnotationConfigApplicationContext annotationConfigApplicationContext = getAnnotationConfigApplicationContext();
        printBeans(annotationConfigApplicationContext);

        // 获取Bean
        CatEntity initializingAndDisposableBean = annotationConfigApplicationContext.getBean("initializingAndDisposableBean", CatEntity.class);
        System.out.println(initializingAndDisposableBean);

        // 关闭IOC容器
        annotationConfigApplicationContext.close();
        System.out.println(initializingAndDisposableBean);
    }

    /**
     * 借助JSR250的@PostConstruct和@PreDestroy注解自定义Bean初始化后、销毁前处理流程
     */
    private static void jsr250() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = getAnnotationConfigApplicationContext();
        ;
        annotationConfigApplicationContext.close();
    }

    /**
     * 借助BeanPostProcess接口，自定义所有Bean的初始化后置处理流程
     *
     * @see com.xzy.spring.demo.postprocess.MyBeanPostProcessor
     */
    public static void myBeanPostProcess() {
        // 详情见MyBeanPostProcessor
        AnnotationConfigApplicationContext annotationConfigApplicationContext = getAnnotationConfigApplicationContext();
        printBeans(annotationConfigApplicationContext);
        annotationConfigApplicationContext.close();
    }

    /**
     * 使用@Value进行属性赋值
     */
    public static void propertiesAssigment() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = getAnnotationConfigApplicationContext();
        printBeans(annotationConfigApplicationContext);
        AuthorEntity propertiesAssignment = annotationConfigApplicationContext.getBean("propertiesAssignment", AuthorEntity.class);
        System.out.println(propertiesAssignment);

        // 配置信息最终会被加载到运行环境，因此也可以通过运行环境获取。
        ConfigurableEnvironment environment = annotationConfigApplicationContext.getEnvironment();
        String property = environment.getProperty("author.name");
        System.out.println("author.name=" + property);
    }

    /*Supporters*/

    private static void printBeans(ApplicationContext applicationContext) {
        System.out.println("\n已注册的组件：");
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        System.out.println("");
    }

    private static ClassPathXmlApplicationContext getClassPathXmlApplicationContext() {
        return new ClassPathXmlApplicationContext("beans.xml");
    }

    private static AnnotationConfigApplicationContext getAnnotationConfigApplicationContext() {
        return new AnnotationConfigApplicationContext(BeansConfig.class);
    }
}
